﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Globalization;
using System.Net.Mail;
using System.Text;
using Maticsoft.DBUtility;
using Microsoft.Cmp.DataAccess;
using Microsoft.Cmp.Framework;
using Microsoft.SisparkSaaS.Common;
using Microsoft.SisparkSaaS.DAL.Common;
using Microsoft.SisparkSaaS.Entity.Common;

namespace Microsoft.Cmp.InsertMailService
{
    class InsertMail
    {
          /// <summary>
        /// 服务名称
        /// </summary>
        private string ServicesName
        {
            get
            {
                if (_servicesName == string.Empty)
                    _servicesName = GetType().FullName;
                return _servicesName;
            }
        }
        private string _servicesName = string.Empty;
        private readonly WSBO_SendNoticeEmailDAL _wsboSendNoticeEmailDal;

          #region 构造函数
        public InsertMail(WSBO_SendNoticeEmailDAL dal)
        {
            _wsboSendNoticeEmailDal = dal;
            NeedSmtpAuth = true;
            MinRetryTimes = 0;
            MaxRetryTimes = 3;
            NeedSsl = false;
        }
        public InsertMail()
        {
            NeedSmtpAuth = true;
            MinRetryTimes = 0;
            MaxRetryTimes = 3;
            NeedSsl = true;
        }
        #endregion
        #region 公共属性
        /// <summary>
        /// 每次最大发送邮件个数
        /// </summary>
        public int MaxSendCount { get; set; }

        /// <summary>
        /// SMTP服务器地址
        /// </summary>
        public string SmtpServer { get; set; }


        /// <summary>
        /// SMTP服务器端口
        /// </summary>
        public int Port { get; set; }

        /// <summary>
        /// 需要SMTP认证
        /// </summary>
        public bool NeedSmtpAuth { get; set; }

        /// <summary>
        /// 需要SSL连接
        /// </summary>
        public bool NeedSsl { get; set; }

        /// <summary>
        /// 发送邮件时使用的认证用户名
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 发送邮件时使用的认证用户密码
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// 最大尝试次数
        /// </summary>
        public int MaxRetryTimes { get; set; }


        /// <summary>
        /// 最小尝试次数
        /// </summary>
        public int MinRetryTimes { get; set; }

        /// <summary>
        /// 邮件发送者邮件地址
        /// </summary>
        public string MailFrom { get; set; }

        /// <summary>
        /// 邮件发送者显示名称
        /// </summary>
        public string MailFromDisplayName { get; set; }

        /// <summary>
        /// 订单产品到期多少天（月）前，发邮件
        /// </summary>
        public int BeforeDate { get; set; }

        /// <summary>
        /// 订单产品到期前计算单位month，day
        /// </summary>
        public string BeforeSendUnit { get; set; }

        /// <summary>
        /// 数据连接字符串
        /// </summary>
        public string SqlConnectString { get; set; }

        /// <summary>
        /// 每月哪几号启动服务
        /// </summary>
        public string[] SendMailStartDay { get; set; }

        /// <summary>
        /// 运营商管理员邮件地址
        /// </summary>
        public string NoticeOpAdminMail { get; set; }

        /// <summary>
        /// 订单产品到期后多少day时给运营商管理员发邮件
        /// </summary>
        public int NoticeOpAdminMailDay { get; set; }
        #endregion

        /// <summary>
        /// 执行服务
        /// </summary>
        public void Execute()
        {
            Log.Info(ServicesName, "开始运行添加邮件服务。");
            try
            {
                LoadConfig();
                InsertMailtoDb();
                InsertNoticeOpAdminMail();
                if (
                  string.Join(",", SendMailStartDay).Contains(DateTime.Today.Day.ToString(CultureInfo.InvariantCulture)))
                {
                    DoExecute();
                }
            }
            catch (Exception ex)
            {
                //记录到数据库
                Log.Error(ServicesName + "执行服务异常", ex);
            }
            Log.Info(ServicesName, "添加邮件服务运行结束。");
        }
        /// <summary>
        /// 加载配置文件
        /// </summary>
        private void LoadConfig()
        {
            MaxSendCount = Convert.ToInt32(ConfigurationManager.AppSettings["MaxSendCount"]);

            string smtp = ConfigurationManager.AppSettings["SMTPServer"];
            int port = 25;
            if (smtp == "")
                throw new Exception("SMTP服务器配置错误。");
            int i = smtp.IndexOf(":", StringComparison.Ordinal);
            if (i >= 0)
            {
                if (i == 0 || !Int32.TryParse(smtp.Substring(i + 1), out port))
                    throw new Exception("SMTP服务器配置错误。");
                smtp = smtp.Substring(0, i);
            }
            SmtpServer = smtp;
            Port = port;


            try
            {
                NeedSmtpAuth = Boolean.Parse(ConfigurationManager.AppSettings["NeedSMTPAuth"]);

                NeedSsl = Boolean.Parse(ConfigurationManager.AppSettings["NeedSSL"]);

                UserName = ConfigurationManager.AppSettings["UserName"];

                Password = ConfigurationManager.AppSettings["Password"];
                MailFrom = ConfigurationManager.AppSettings["MailFrom"];
                MailFromDisplayName = ConfigurationManager.AppSettings["MailFromDisplayName"];
                SqlConnectString = ConfigurationManager.ConnectionStrings["SqlConnectString"].ToString();
                DbHelperSQL.connectionString = SqlConnectString;
                MaxRetryTimes = Convert.ToInt32(ConfigurationManager.AppSettings["MaxRetryTimes"]);
                MinRetryTimes = Convert.ToInt32(ConfigurationManager.AppSettings["MinRetryTimes"]);
                BeforeSendUnit = ConfigurationManager.AppSettings["BeforeSendUnit"];
                BeforeDate = int.Parse(ConfigurationManager.AppSettings["BeforeDate"]);
                NoticeOpAdminMail = ConfigurationManager.AppSettings["NoticeOpAdminMail"];
                NoticeOpAdminMailDay = int.Parse(ConfigurationManager.AppSettings["NoticeOpAdminMailDay"]);
                var sendday = ConfigurationManager.AppSettings["SendMailStartDay"];
                SendMailStartDay = sendday.Split(',');
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "加载配置文件异常", ex);
            }
        }
        /// <summary>
        /// 获得企业用户购买的快到期的产品列表
        /// </summary>
        public DataTable GetEcOrdersProduct()
        {
            var dt = new DataTable();
            try
            {
                var sqlCommand = new StringBuilder();
                sqlCommand.AppendFormat(
                    "SELECT * FROM {0}  where  EndTime>GETDATE() and EndTime<=DATEADD({1},{2},GETDATE()) and OpenStatus=0 ORDER BY EndTime ASC ",
                    "vw_EC_Ordors_Product", BeforeSendUnit, BeforeDate);
                var ds = DbHelperSQL.Query(sqlCommand.ToString());

                dt = ds.Tables[0];
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "获得企业用户购买的快到期的产品列表时发生异常", ex);
            }
            return dt;
        }

        /// <summary>
        /// 添加符合产品到期条件的新邮件
        /// </summary>
        protected void InsertMailtoDb()
        {
            try
            {
                DataTable dt = GetEcOrdersProduct();
                if (dt.Rows.Count > 0)
                {
                    var list = new List<WSBO_SendNoticeEmailInfo>();
                    foreach (DataRow dr in dt.Rows)
                    {
                        var ecOrdorsProductInfo = new vw_EC_Ordors_ProductInfo();
                        DataToObject.GetDataFromDataRow(ecOrdorsProductInfo, dr);
                        if (!_wsboSendNoticeEmailDal.Exists(ecOrdorsProductInfo.OrderID))
                        {
                            var mEmailInfo = new WSBO_SendNoticeEmailInfo
                            {
                                CreateTime = DateTime.Now,
                                EmailTo = ecOrdorsProductInfo.CompanyEmail,
                                EmailFrom = MailFrom,
                                EmailDisplayName = MailFromDisplayName,
                                OrderID = ecOrdorsProductInfo.OrderID,
                                SendStatus = (int)MailStatus.NotSent,
                                EmailSubject = "《" + ecOrdorsProductInfo.OrderName + "》产品到期续费通知",
                                Type = (int)MailType.ProductOutDate
                            };
                            var content = new SmtpMessage().OrderProductInfoToUserPass(ecOrdorsProductInfo.CompanyName,
                                                                                       ecOrdorsProductInfo.OrderName,
                                                                                       ecOrdorsProductInfo.EndTime.
                                                                                           ToString("yyyy-MM-dd"));
                            mEmailInfo.EmailTextBody = content[1];
                            mEmailInfo.EmailHtmlBody = content[0];
                            list.Add(mEmailInfo);
                            Log.Info(ServicesName + "写入产品到期通知邮件",
                                     string.Format("邮件接受者：{0}，到期产品：{1}，到期日期：{2}，邮件创建时间：{3}", mEmailInfo.EmailTo,
                                                   ecOrdorsProductInfo.OrderName, ecOrdorsProductInfo.EndTime.
                                                                                      ToString("yyyy-MM-dd"),
                                                   mEmailInfo.CreateTime));
                        }
                    }
                    _wsboSendNoticeEmailDal.Add(list);
                }
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "添加符合产品到期条件的新邮件时发生异常", ex);
            }
        }


        /// <summary>
        /// 获得企业用户购买的已过期的产品列表
        /// </summary>
        public DataTable GetEcOrdersoutofdateProduct()
        {
            var dt = new DataTable();
            try
            {
                var sqlCommand = new StringBuilder();
                sqlCommand.AppendFormat(
                    "SELECT * FROM {0}  where  EndTime=DATEADD(day,{1},GETDATE()) and OpenStatus=0 ORDER BY EndTime ASC ",
                    "vw_EC_Ordors_Product", NoticeOpAdminMailDay);
                var ds = DbHelperSQL.Query(sqlCommand.ToString());

                dt = ds.Tables[0];
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "获得企业用户购买的已过期的产品列表时发生异常", ex);
            }
            return dt;
        }

        /// <summary>
        /// 添加符合产品到期后通知条件的新邮件
        /// </summary>
        protected void InsertNoticeOpAdminMail()
        {
            try
            {
                DataTable dt = GetEcOrdersoutofdateProduct();
                if (dt.Rows.Count > 0)
                {
                    var list = new List<WSBO_SendNoticeEmailInfo>();
                    foreach (DataRow dr in dt.Rows)
                    {
                        var ecOrdorsProductInfo = new vw_EC_Ordors_ProductInfo();
                        DataToObject.GetDataFromDataRow(ecOrdorsProductInfo, dr);

                        var mEmailInfo = new WSBO_SendNoticeEmailInfo
                        {
                            CreateTime = DateTime.Now,
                            EmailTo = NoticeOpAdminMail,
                            EmailFrom = MailFrom,
                            EmailDisplayName = MailFromDisplayName,
                            OrderID = ecOrdorsProductInfo.OrderID,
                            SendStatus = (int)MailStatus.NotSent,
                            EmailSubject = "《" + ecOrdorsProductInfo.OrderName + "》产品已过期通知",
                            Type = (int)MailType.OtherMail,
                            EmailTextBody =
                                string.Format(ecOrdorsProductInfo.CompanyName + "购买的产品《" +
                                              ecOrdorsProductInfo.OrderName +
                                              "》已于" + ecOrdorsProductInfo.EndTime.
                                                          ToString("yyyy-MM-dd") + "过期，请处理。")
                        };
                        //mEmailInfo.EmailHtmlBody = content[0];
                        list.Add(mEmailInfo);
                        Log.Info(ServicesName + "写入产品已过期通知邮件",
                                 string.Format("邮件接受者：{0}，到期产品：{1}，到期日期：{2}，邮件创建时间：{3}", mEmailInfo.EmailTo,
                                               ecOrdorsProductInfo.OrderName, ecOrdorsProductInfo.EndTime.
                                                                                  ToString("yyyy-MM-dd"),
                                               mEmailInfo.CreateTime));

                    }
                    _wsboSendNoticeEmailDal.Add(list);
                }
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "添加符合产品到期条件的新邮件时发生异常", ex);
            }
        }
        /// <summary>
        /// 发送产品到期的邮件
        /// </summary>
        private void DoExecute()
        {

            //获取待发送的邮件
            DataTable dataSource = GetPendingMail(MaxSendCount, MinRetryTimes, MaxRetryTimes);

            while (dataSource.Rows.Count > 0)
            {
                Log.Info(ServicesName, string.Format("获取待发送邮件：{0} 条.", dataSource.Rows.Count));
                var list = new List<WSBO_SendNoticeEmailInfo>();
                foreach (DataRow dr in dataSource.Rows)
                {
                    try
                    {
                        var mail = new WSBO_SendNoticeEmailInfo();
                        DataToObject.GetDataFromDataRow(mail, dr);
                        if (string.IsNullOrEmpty(mail.EmailFrom))
                        {
                            mail.EmailFrom = MailFrom;
                        }
                        if (string.IsNullOrEmpty(mail.EmailTo) || string.IsNullOrEmpty(mail.EmailFrom))
                        {
                            mail.SendStatus = (int)MailStatus.SentFailed;
                            mail.SendFailedCount = MaxRetryTimes;
                            Log.Info(ServicesName,
                                     string.Format("ID = {0} 的邮件的发送信息部完整，发件人：{1}，收件人：{2}。", mail.EmailGuid,
                                                   mail.EmailFrom,
                                                   mail.EmailTo));
                        }
                        else
                        {
                            DoSendMail(mail);
                        }
                        mail.ModifyTime = DateTime.Now;
                        list.Add(mail);

                    }
                    catch (Exception ex)
                    {
                        Log.Error(ServicesName + "发送邮件异常", ex);
                    }
                }
                try
                {
                    _wsboSendNoticeEmailDal.UpdateMail(list);
                    //删除已发送的邮件
                    _wsboSendNoticeEmailDal.Delete(list);
                }
                catch (Exception exception)
                {

                    Log.Error(ServicesName + "发送邮件批量处理的时候发生异常", exception);
                }
                //继续获取待发送的邮件
                dataSource = GetPendingMail(MaxSendCount, MinRetryTimes, MaxRetryTimes);
            }

        }
        /// <summary>
        /// 获取产品到期通知的邮件
        /// </summary>
        public DataTable GetPendingMail(int queryCount, int minRetryTimes, int maxRetryTimes)
        {
            var dt = new DataTable();
            try
            {
                var sqlCommand = new StringBuilder();
                //邮件状态为未发送或者发送失败，且发送失败次数少于3，发送成功次数小于发送日期，按照最后修改时间正序排列

                #region 获取产品到期通知的邮件

                sqlCommand.AppendFormat(
                    "SELECT TOP {0} * FROM {1}  WHERE (SendStatus = {2} or SendStatus={3}) AND SendFailedCount >= {4} AND SendFailedCount < {5} " +
                    "  and Type={6} ORDER BY ModifyTime ASC ",
                    queryCount, "WSBO_SendNoticeEmail", (int)MailStatus.NotSent, (int)MailStatus.SentFailed,
                    minRetryTimes,
                    maxRetryTimes,
                    (int)MailType.ProductOutDate);
                //sqlCommand.AppendFormat(
                //    "SELECT* from WSBO_SendNoticeEmail where EmailGuid='907ABF5D-D759-4446-A6EB-32ECA1E86020'  and (SendSuccessCount IS NULL OR SendSuccessCount<{0})",
                //    maxRetryTimes);
                var ds = DbHelperSQL.Query(sqlCommand.ToString());
                dt = ds.Tables[0];

                #endregion
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName + "获取产品到期通知的邮件时发生异常", ex);
            }
            return dt;
        }
        private void DoSendMail(WSBO_SendNoticeEmailInfo mail)
        {
            var client = new SmtpClient(SmtpServer, Port);
            if (NeedSmtpAuth)
                client.Credentials = new System.Net.NetworkCredential(UserName, Password);
            if (NeedSsl)
                client.EnableSsl = true;
            //client.DeliveryMethod = SmtpDeliveryMethod.Network;
            MailMessage message = MakeMessage(mail);
            mail.SendStatus = (int)MailStatus.SentNow;
            Log.Info(ServicesName,
                     string.Format("正在发送ID = {0} 的邮件，发件人：{1}，收件人：{2}。", mail.EmailGuid, mail.EmailFrom,
                                   mail.EmailTo));
            try
            {
                client.Send(message);
                //发送成功
                mail.SendStatus = (int)MailStatus.SentSuccess;
                Log.Info(ServicesName,
                         string.Format("ID = {0} 的邮件发送成功，发件人：{1}，收件人：{2}。", mail.EmailGuid, mail.EmailFrom, mail.EmailTo));
            }
            catch (Exception ex)
            {
                Log.Error(ServicesName,
                          string.Format("ID = {0} 的邮件发送失败，失败原因：{1}", mail.EmailGuid, ex.Message));

                //如果发生异常，那么需要将邮件发送次数加1，并标记为发送失败
                mail.SendStatus = (int)MailStatus.SentFailed;
                mail.SendFailedCount += 1;
            }
            finally
            {
                message.Dispose();
            }
        }

        private MailMessage MakeMessage(WSBO_SendNoticeEmailInfo mail)
        {
            var msg = new MailMessage
            {
                From = !string.IsNullOrEmpty(mail.EmailDisplayName)
                           ? new MailAddress(mail.EmailFrom, mail.EmailDisplayName)
                           : new MailAddress(mail.EmailFrom)
            };
            foreach (string to in mail.EmailTo.Split(';'))
            {
                if (to.Trim() != string.Empty)
                    msg.To.Add(to);
            }

            msg.SubjectEncoding = Encoding.GetEncoding("GB2312");
            msg.BodyEncoding = Encoding.GetEncoding("GB2312");
            msg.Headers["Encoding"] = Encoding.GetEncoding("GB2312").ToString();
            //msg.SubjectEncoding = System.Text.Encoding.UTF8;
            //msg.BodyEncoding = System.Text.Encoding.UTF8;
            //msg.Headers["Encoding"] = System.Text.Encoding.UTF8.ToString();
            if (!string.IsNullOrEmpty(mail.EmailHtmlBody))
            {
                msg.IsBodyHtml = true;
                msg.Body = mail.EmailHtmlBody;
            }
            else
            {
                msg.Body = mail.EmailTextBody;
            }
            msg.Subject = mail.EmailSubject;
            if (!string.IsNullOrEmpty(mail.EmailCC))
            {
                foreach (string cc in mail.EmailCC.Split(';'))
                {
                    if (cc.Trim() != string.Empty)
                        msg.CC.Add(cc);
                }
            }
            if (!string.IsNullOrEmpty(mail.EmailBCC))
            {
                foreach (string bcc in mail.EmailBCC.Split(';'))
                {
                    if (bcc.Trim() != string.Empty)
                        msg.Bcc.Add(bcc);
                }
            }
            return msg;
        }


    }
}
